﻿using System;
using System.Data;
using System.Linq;
using System.Linq.Expressions;
using NHibernate;
using NHibernate.Linq;
using Tools.Common.UnitOfWork.Contracts;
using Tools.Common.UnitOfWork;
using IsolationLevel=Tools.Common.UnitOfWork.IsolationLevel;

namespace Web.App.Infrastructure.UnitOfWork.Implementations
{
    [Serializable]
    public class NHibernateUoW : IUnitOfWork, IUoWSession
    {
        private Guid id;
        private Tools.Common.UnitOfWork.ConversationType type;
        private ISession session;

        public NHibernateUoW(ISession session, ConversationType type, Guid id)
        {
            this.session = session;
            this.id = id;
            this.type = type;
        }

        public void TransactionalFlush(IsolationLevel isolationLevel)
        {
            IUoWTransaction tx = BeginTransaction(isolationLevel);
            try
            {
                //forces a flush of the current unit of work
                tx.Commit();
            }
            catch
            {
                tx.Rollback();
                throw;
            }
            finally
            {
                tx.Dispose();
            }
        }

        public Guid ID
        {
            get { return id; }
        }

        public ConversationType ConversationType
        {
            get { return type; }
        }



        public void Flush()
        {
            session.Flush();
        }

        public bool IsInActiveTransaction
        {
            get { return session.Transaction.IsActive; }
        }

        public IUoWTransaction BeginTransaction()
        {
            return new NHibernateUoWTransaction(session.BeginTransaction());
        }

        public IUoWTransaction BeginTransaction(IsolationLevel isolationLevel)
        {
            return new NHibernateUoWTransaction(session.BeginTransaction());
        }


        public void TransactionalFlush()
        {
            
            TransactionalFlush(IsolationLevel.ReadCommitted);
        }


        public object CurrentSession
        {
            get { return session; }
        }

        public void Dispose()
        {
            session.Close();
            session.Dispose();
        }

        public void Save<T>(T entity)
        {
            session.Save(entity);
        }

        public void SaveOrUpdate<T>(T entity)
        {
            session.SaveOrUpdate(entity);
        }

        public void Delete<T>(T entity)
        {
            session.Delete(entity);
        }

        public void Refresh<T>(T entity)
        {
            session.Refresh(entity);
        }

        public IQueryable<T> Query<T>(Expression<Func<T, bool>> predicate)
        {
            return session
                    .Linq<T>()
                    .Where(predicate);
        }

        public T LoadById<T>(object id)
        {
            return session.Load<T>(id);
        }

        public void Reconnect()
        {
            session.Reconnect();
        }

        public void Disconnect()
        {
            session.Disconnect();
        }
    }
}
